#ifndef DAQ_H
#define DAQ_H

#include <inttypes.h>
#include "../util/util.h"
#include "../packets/crc.h"
#include "../ftd2xx.h"

#include "../packets/structs/adcPacketStructs.h"
#include "../packets/structs/dacPacketStructs.h"
#include "../packets/structs/dioPacketStructs.h"
#include "../packets/structs/encPacketStructs.h"
#include "../packets/structs/genPacketStructs.h"
#include "../packets/structs/msgHeaderDefs.h"
#include "../packets/structs/pwmPacketStructs.h"
#include "../packets/structs/tmrPacketStructs.h"



#define bufferSize  65536

#define numberOfSamples 1024


class ringBuffer
{
 public:
    uint8_t *bufferBegin;
    uint8_t *bufferEnd;
    volatile uint8_t *head;
    volatile  uint8_t *tail;
    volatile  uint32_t bytesInBuffer;
    bool    dataOverFlow;
    uint8_t data[bufferSize];

    ringBuffer();
};

uint16_t packetSizeLookup(uint8_t msgHeader);

//this function pulls packets out of rx buffer
uint8_t comPortGet();

//this function processes messages found with comPorGet
void processData(uint8_t *packet);

uint8_t bufferRead();
void bufferWrite(char c);

void receiveFunc();

void FTError(FT_STATUS status);

FT_HANDLE   comPortInit(DWORD baud, uint16_t rxTime, uint16_t txTime);

void        comPortClose(FT_HANDLE handle);

uint16_t    comPortPut(FT_HANDLE handle, uint8_t *packet, uint8_t length);

namespace DAQ_namespace
{

    class DAQALLOC
    {




public:


        //settingPending flags will halt additional settings until the first is heard
        //example:
        //if adc channel 0 is set to 2x gain wait for the confirmation till
        //allowing a msg to set the gain to 4x
        //settingPending(s) + watchdog(s) can be used to resend commands

        struct analogInAlloc{
            bool    settingPending;
            bool    enable;
            bool    sign;
            GAIN_t  gain;
            SMPD_t  samples;
            RES_t   resolution;
        }analogIn[4];

        struct analogOutAlloc{
            bool    settingPending;
            bool    enable;
        }analogOut[2];

        //settings other than enable should be set by this program
        //ack error codes should tell whether a message was received correctly
        //there should be prevention from assigning the same encoder different values per run
        struct encoderAlloc{
            bool        settingPending;
            bool        enable;
            bool        absolute;
            bool        index;
            PLOC_t      PLOC;
            uint16_t    resolution;    //prior to upscaling
        }encoder[2];

        struct digitalAlloc{
            bool    inSettingPending;
            bool    outSettingPending;
            bool    inEnable;
            bool    outEnable;
            bool    dioAlloc[13];
            bool    dir[13];        //direction for the pin
        }digital;

        struct motorAlloc{
            bool        settingPending;
            bool        enable;
        }motor[4];

        struct servoAlloc{
            bool        settingPending;
            bool        enable;
        }servo[4];

        struct genAlloc
        {
            bool        startPending;
            bool        stopPending;
            bool        actuatorSuperPending;
            bool        outputSuperPending;
        }general;

        struct timerAlloc
        {
            bool        settingPending;
            bool        enable;
            uint16_t    loopTime;
        }timer;

        DAQ_STATE_t   state;

        DAQALLOC();

        void analogInConfig(uint8_t errorCode);
        void analogOutConfig(uint8_t errorCode);
        void encoderConfig(uint8_t errorCode);
        void encDioConfig(uint8_t encNum);
        void digitalInConfig(uint8_t errorCode);
        void digitalOutConfig(uint8_t errorCode);
        void motorConfig(uint8_t errorCode);
        void servoConfig(uint8_t errorCode);

        void startConfig(uint8_t errorCode);
        void stopConfig(uint8_t errorCode);
        void readyConfig(uint8_t errorCode);
        void tmrConfig(uint8_t errorCode);

        //these functions will assess what features are enabled
        uint8_t getOutputSuperPacketLength();
        uint8_t getInputSuperPacketLength();
        uint8_t getActuatorSuperPacketLength();

        //advanced
        void sendAdcInit(FT_HANDLE handle, ACHM_t adcMsk,bool sign,GAIN_t adcGain,SMPD_t sampleDepth,RES_t resolution);

        //simple
        status_t sendAdcInit(FT_HANDLE handle, uint8_t adcMsk, GAIN_t adcGain);

        status_t sendDacEnable(FT_HANDLE handle, DACM_t DACM);

        status_t sendDigitalInEnable(FT_HANDLE handle);
        status_t sendDigitalOutEnable(FT_HANDLE handle);

        status_t sendEncoderInit(FT_HANDLE handle, PLOC_t PLOC, bool index, uint8_t num, bool ABS, DIGFILT_t EDFL, uint16_t resolution);

        status_t sendMotorEnable(FT_HANDLE handle, uint8_t msk);
        status_t sendServoEnable(FT_HANDLE handle, uint8_t msk);

        status_t sendSetTimerFreq(FT_HANDLE handle,uint16_t freq);

        status_t sendStartProgram(FT_HANDLE handle);
        status_t sendStopProgram(FT_HANDLE handle);

        status_t sendOutputSuperPacket(FT_HANDLE handle, uint16_t analogOut[], uint16_t dioSet, uint16_t dioClr);
        status_t sendActuatorSuperPacket(FT_HANDLE handle, uint16_t servoPosition[], uint16_t motorEffort[]);

        void inputSuperPacketHandler(uint8_t packet[]);
    };


}
#endif // DAQ_H
